機(jī)器人小強(qiáng)一號(hào)的制作過(guò)程
從對(duì)機(jī)器人感興趣開(kāi)始,買了一堆書(shū),也看了很多資料,決定先從最簡(jiǎn)單的車輪機(jī)器人開(kāi)始做。普通電腦雖然強(qiáng)大,但是不能直接采集外界環(huán)境的物理數(shù)據(jù),也不能直接控制電機(jī)。查找了下,雖然可以直接在電腦上接USB接口的數(shù)據(jù)采集器用于采集傳感器的數(shù)據(jù),也可以使用PCI的電機(jī)控制卡來(lái)驅(qū)動(dòng)各種電機(jī),不過(guò)成本有些高,暫時(shí)不考慮了。找了一圈,發(fā)現(xiàn)還是單片機(jī)方案廉價(jià),順便可以學(xué)習(xí)下單片機(jī)控制和作一些電路實(shí)驗(yàn)。于是最終決定實(shí)驗(yàn)方案采用單片機(jī)來(lái)做了。
零件
下面是采購(gòu)的零件:
8位單片機(jī)Atmega168開(kāi)發(fā)板。
電路面包板和連線用于驅(qū)動(dòng)車輪的兩個(gè)減速電機(jī)。沒(méi)有找到合適的齒輪,自己也沒(méi)有加工設(shè)備,圖簡(jiǎn)單,所以直接用集成減速齒輪的電機(jī)代替了。
距離傳感器,作為機(jī)器人的主要傳感器,用來(lái)探測(cè)障礙物的距離。使用的是常用的紅外距離傳感器作為機(jī)器人的眼睛。
舵機(jī),用來(lái)控制機(jī)器人“眼睛”的方向。
下一步就可以驗(yàn)證簡(jiǎn)單的功能了。
實(shí)驗(yàn)
接下來(lái)先搞清楚怎么用單片機(jī)。
Hello world
先讓單片機(jī)跑起來(lái)再說(shuō)。習(xí)慣了操作系統(tǒng)下編程,第一次用單片機(jī)還真有些不習(xí)慣,擔(dān)心遇到問(wèn)題,不過(guò)比較順利。這個(gè)程序用來(lái)點(diǎn)亮
單片機(jī)上的一個(gè)LED。
代碼:
int ledPin = 13; // LED connected to digital pin 13
<!--[if !supportEmptyParas]--> <!--[endif]-->
void setup()
{
pinMode(ledPin, OUTPUT); // sets the digital pin as output
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
void loop()
{
digitalWrite(ledPin, HIGH); // sets the LED on
delay(1000); // waits for a second
digitalWrite(ledPin, LOW); // sets the LED off
delay(1000); // waits for a second
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
以間隔1000ms的時(shí)間把單片機(jī)的第13 個(gè)Pin腳循環(huán)輸出高低電平,從而達(dá)到點(diǎn)亮和熄滅LED功能。很簡(jiǎn)單,就是驗(yàn)證下單片機(jī)是否可用。
控制舵機(jī)
舵機(jī)就是遙控模型上用來(lái)控制的,其實(shí)就是一個(gè)帶閉環(huán)控制的電機(jī),能轉(zhuǎn)動(dòng)到指定的角度。
工作原理是:控制信號(hào)由接收機(jī)的通道進(jìn)入信號(hào)調(diào)制芯片,獲得直流偏置電壓。它內(nèi)部有一個(gè)基準(zhǔn)電路,產(chǎn)生周期為20ms,寬度為1.5ms的基準(zhǔn)信號(hào),將獲 得的直流偏置電壓與電位器的電壓比較,獲得電壓差輸出。
最后,電壓差的正負(fù)輸出到電機(jī)驅(qū)動(dòng)芯片決定電機(jī)的正反轉(zhuǎn)。當(dāng)電機(jī)轉(zhuǎn)速一定時(shí),通過(guò)級(jí)聯(lián)減速齒輪帶動(dòng) 電位器旋轉(zhuǎn),使得電壓差為0,電機(jī)停止轉(zhuǎn)動(dòng)。
在程序中控制舵機(jī)的轉(zhuǎn)動(dòng)角度,就是生成不同脈寬的PWM就行了。
上面的代碼簡(jiǎn)單的生成一個(gè)PWM 驅(qū)動(dòng)舵機(jī)旋轉(zhuǎn),比較簡(jiǎn)單。 代碼中用delay來(lái)實(shí)現(xiàn)延時(shí),如果是同時(shí)控制多個(gè)舵機(jī),用這樣的代碼是不行的,需要自己計(jì)算時(shí)間。因?yàn)橛胐elay整個(gè)單片機(jī)都“休息”了,無(wú)法執(zhí)行任何代碼。在實(shí)際實(shí)現(xiàn)中,還需要不斷的讀取傳感器輸入和進(jìn)行其他處理。
紅外距離傳感器
傳感器介紹:
SHARP紅外距離傳感器,用于模型或機(jī)器人制作,可以用來(lái)測(cè)量距離。每個(gè)模塊贈(zèng)送一根15cm長(zhǎng)PH2.0的單頭排線.
<!--[if !supportEmptyParas]--> <!--[endif]-->
技術(shù)規(guī)格:
<!--[if !supportEmptyParas]--> <!--[endif]-->
探測(cè)距離:10-80cm
工作電壓:4-5.5V
標(biāo)準(zhǔn)電流消耗:33-50 mA
輸出量:模擬量輸出,輸出電壓和探測(cè)距離成比例
接好電源,把模擬信號(hào)輸出端接在單片機(jī)的模擬輸入Pin就行了。
測(cè)試代碼:
int potPin = 2;
int ledPin = 13;
int val = 0;
<!--[if !supportEmptyParas]--> <!--[endif]-->
void setup() {
pinMode(ledPin, OUTPUT);
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
void loop() {
val = analogRead(potPin);
digitalWrite(ledPin, HIGH);
delay(val);
digitalWrite(ledPin, LOW);
delay(val);
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
運(yùn)行結(jié)果,led隨著傳感器距離的變化閃爍間隔也隨著變化。
控制電機(jī)
常用的直流電機(jī)使用L293D來(lái)控制,使用H293的電路如下:
不過(guò)在驗(yàn)證是發(fā)現(xiàn),對(duì)于小電機(jī),直接用單片機(jī)的PWM端子來(lái)輸出不同電壓的來(lái)控制速度也是可行的,雖然不太精確,但是對(duì)于實(shí)現(xiàn)運(yùn)動(dòng)特征是足夠了。單片機(jī)無(wú)法輸出真正的線性模擬電壓,PWM是通過(guò)調(diào)整空占比間隔來(lái)模擬不同電壓值的。
測(cè)量了電機(jī)在空載和負(fù)載情況下電流都只有幾十毫安,所以先采取這種簡(jiǎn)單的辦法驗(yàn)證。
直接把電機(jī)接到單片機(jī)的Gnd和 PWM Pin 9接口,然后在程序中直接向 Pin 9輸出就可以讓電機(jī)運(yùn)轉(zhuǎn)了。
int value = 0;
int ledpin = 9;
<!--[if !supportEmptyParas]--> <!--[endif]-->
void setup()
{
// nothing for setup
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
void loop()
{
for(value = 0 ; value <= 255; value+=5)
{
analogWrite(ledpin, value);
delay(30);
}
for(value = 255; value >=0; value-=5)
{
analogWrite(ledpin, value);
delay(30);
}
}
<!--[if !supportEmptyParas]--> <!--[endif]-->
上面的程序用不同的輸出值驅(qū)動(dòng)電機(jī),可以看到電機(jī)的旋轉(zhuǎn)效果。
<!--[if !supportEmptyParas]--> <!--[endif]-->
單片機(jī)和主要部件的驗(yàn)證基本就完成了,下一步要開(kāi)始程序設(shè)計(jì)了。
軟件設(shè)計(jì)
思路
在進(jìn)行代碼編寫(xiě)之前,想找到一種簡(jiǎn)介的實(shí)現(xiàn)低級(jí)智能機(jī)器人的方式。目前的工業(yè)機(jī)器人采用的是精確控制的方法,在程序中固化每種處理邏輯。用程序員的思維來(lái)完成對(duì)機(jī)器人的操作。
對(duì)于程序員來(lái)說(shuō),機(jī)器人無(wú)非就是外接了物理傳感輸入和運(yùn)動(dòng)控制輸出的一臺(tái)電腦,不管是64位多核CPU或者8位單片機(jī),只是性能的不同而已。理論上,都能通過(guò)程序設(shè)計(jì)來(lái)達(dá)到預(yù)定的目標(biāo)。如果按照計(jì)算機(jī)上的普通程序來(lái)設(shè)計(jì),那么大量的功能代碼會(huì)相互耦,每次為了增加一個(gè)新的運(yùn)動(dòng)功能或者任務(wù),都需要編制新的代碼,而新的代碼給原來(lái)的環(huán)路反饋系統(tǒng)帶來(lái)新的邏輯分支,所有的步驟都得經(jīng)過(guò)程序員的驗(yàn)證和設(shè)計(jì)。這樣的設(shè)計(jì)對(duì)于精確計(jì)算的PC程序或者擅長(zhǎng)固定場(chǎng)景精確動(dòng)作的工業(yè)機(jī)器人來(lái)說(shuō),都沒(méi)有問(wèn)題。但是對(duì)于這里要實(shí)現(xiàn)的“小強(qiáng)一號(hào)”機(jī)器人,是處在一個(gè)動(dòng)態(tài)的變化環(huán)境當(dāng)中,如果按照傳統(tǒng)的軟件設(shè)計(jì)邏輯,會(huì)存在大量耦合的邏輯分支,導(dǎo)致程序擴(kuò)展性很差。舉例來(lái)說(shuō),為了完成一個(gè)沿墻壁行走的功能,必須對(duì)各種傳感器輸入情況進(jìn)行判斷,然后做出預(yù)置的動(dòng)作序列。
如果要執(zhí)行的動(dòng)作和需要判斷的情況很多,那么程序邏輯分支就比較復(fù)雜,擴(kuò)展性也比較差,有沒(méi)有更好的適合機(jī)器人軟件設(shè)計(jì)的方法呢?
換一種思維來(lái)思考的話,我們要做的不是電腦程序,只是一個(gè)實(shí)驗(yàn)機(jī)器人。這個(gè)實(shí)驗(yàn)機(jī)器人能做到自然界昆蟲(chóng)級(jí)的“智能”就很不錯(cuò)了。 試想,一只螞蟻,一只蟑螂會(huì)去思考這么復(fù)雜的邏輯分支嗎?去考慮各種情況下應(yīng)該采取的動(dòng)作? 不太可能。我們用了復(fù)雜的想法去解決簡(jiǎn)單的事情。
機(jī)器人和計(jì)算機(jī)的主要區(qū)別在于,計(jì)算機(jī)是按照預(yù)先規(guī)劃的指令運(yùn)行,而機(jī)器人需要根據(jù)變化的環(huán)境選擇合適動(dòng)作。我們首先可以簡(jiǎn)化動(dòng)作模型,我把機(jī)器人的執(zhí)行任務(wù)分成3個(gè)層次:任務(wù)-》行為-》動(dòng)作任務(wù)——機(jī)器人完成的一個(gè)期望目標(biāo),比如“在一個(gè)范圍內(nèi)收集地面上的垃圾”可以界定為一個(gè)機(jī)器人的任務(wù)。
行為——行為是對(duì)任務(wù)的分解,行為是機(jī)器人根據(jù)環(huán)境變化選擇要做什么。比如碰到墻壁需要進(jìn)行躲避。電源不足需要充電,就可以劃分為一個(gè)行為。
動(dòng)作——機(jī)器人最終控制電機(jī)等輸出設(shè)備做出的動(dòng)作,比如前進(jìn),后退,轉(zhuǎn)彎。轉(zhuǎn)動(dòng)攝像頭都可以劃分成一個(gè)動(dòng)作單元。
說(shuō)明:任務(wù)由一系列的行為構(gòu)成;行為有一個(gè)或者多個(gè)動(dòng)作組成,動(dòng)作是立即執(zhí)行的最小單元。在任意一個(gè)時(shí)刻,只有一個(gè)動(dòng)作可以得到執(zhí)行。
軟件實(shí)現(xiàn)的對(duì)象就是分解出簡(jiǎn)單的行為,針對(duì)每個(gè)行為單獨(dú)實(shí)現(xiàn),互相之間無(wú)干涉、無(wú)耦合。當(dāng)多個(gè)行為要輸出互相矛盾的動(dòng)作時(shí),通過(guò)一個(gè)行為優(yōu)先級(jí)表來(lái)決定優(yōu)先級(jí)高的行為來(lái)做出動(dòng)作。在這個(gè)思路中,參考了基于行為編程的理論,關(guān)于詳細(xì)的基于行為編程的描述,可以在網(wǎng)上搜索“Behavior-based robotics”。
通過(guò)這種設(shè)計(jì)思路,可以實(shí)現(xiàn)對(duì)動(dòng)物反射特性的模擬,不需要把精力放在復(fù)雜的邏輯處理上,只需要根據(jù)分解出的基本行為實(shí)現(xiàn)一個(gè)一個(gè)小的行為單元。每個(gè)行為單元只關(guān)心自己的傳感輸入和需要輸出的控制動(dòng)作就行了。確定了設(shè)計(jì)思路,下一部分開(kāi)始針對(duì)小強(qiáng)一號(hào)來(lái)設(shè)計(jì)軟件了。
參考資料,有興趣的可以閱讀:
http://www-robotics.usc.edu/~maja/publications/mitcs.ps.gz (這篇文章描述了如何分解行為,需要安裝 GSView)
http://www.research.ibm.com/people/j/jhc/pubs/jhc-design.pdf
http://www-robotics.usc.edu/~maja/bbs.html
《基于行為的機(jī)器人實(shí)戰(zhàn)指南》 中譯版
強(qiáng)一號(hào)結(jié)構(gòu)非常簡(jiǎn)單,傳感器只采用了個(gè)紅外距離傳感器作為機(jī)器人的“眼睛”,使用兩個(gè)電機(jī)進(jìn)行運(yùn)動(dòng),距離傳感器連接在一個(gè)舵機(jī)上,作為“頭部”可以左右范圍的轉(zhuǎn)動(dòng)。機(jī)器人的行為最簡(jiǎn)單的就是巡航行為,巡航行為就是給電機(jī)電流,電機(jī)轉(zhuǎn)動(dòng)而已。那么發(fā)生碰撞怎么辦?在巡航行為中,不用考慮碰撞,否則又會(huì)變成復(fù)雜的判斷邏輯。為了避免碰撞,設(shè)計(jì)一個(gè)獨(dú)立的避免碰撞的“逃離”行為。逃離行為從距離傳感器獲取障礙物距離信息,簡(jiǎn)單的判斷前方是否有障礙,進(jìn)行避讓。由于多個(gè)行為都可能控制電機(jī),所以需要一個(gè)仲裁器根據(jù)優(yōu)先級(jí)來(lái)判斷到底執(zhí)行那個(gè)邏輯部分輸出的控制指令。
下面用圖來(lái)說(shuō)明這種情況:
如果需要增加其他更加復(fù)雜的智能,那么只需要增加對(duì)應(yīng)的行為單元就行了,不用修改已有的邏輯結(jié)構(gòu)。每個(gè)行為單元只需要處理自己關(guān)心的傳感器和需要控制的動(dòng)作執(zhí)行部分。這種方式的好處就是程序邏輯變得非常簡(jiǎn)單,功能單元之間不會(huì)存在互相影響的弊端。
下面的代碼是“巡航”行為:
class BhCruis:public Behavior
{
public:
publicSPAN style="mso-tab-count: 2">
BhCruis(const char* name):Behavior(name){
};
BhCruis();
void Run();
void Setup();
};
void BhCruis::Setup(){
}
void BhCruis::Run(){
int bid = GetId();
GO_speed_left[bid] = 255;
GO_speed_right[bid] = 255;
GT_beh_action[ACTION_TYPE_MOTOR][bid] = true;
}
上面的代碼很簡(jiǎn)單,就是讓兩個(gè)電機(jī)以同樣的速度暈裝,其他都不用考慮。對(duì)于某些行為,需要引入稍微復(fù)雜一些的處理,比如發(fā)現(xiàn)障礙物,首先要停下來(lái),然后判斷是應(yīng)該往左還是往右,做出決定之后,再進(jìn)行具體的動(dòng)作。針對(duì)這種不能在一個(gè)時(shí)刻完成,要經(jīng)過(guò)幾個(gè)不同的狀態(tài)才能處理完成的行為,可以用狀態(tài)機(jī)來(lái)解決。下圖是“逃離”行為的狀態(tài)機(jī):
對(duì)于行為實(shí)現(xiàn)自己的狀態(tài)機(jī),在行為實(shí)現(xiàn)的代碼內(nèi)部實(shí)現(xiàn),而不影響其他行為。這種結(jié)構(gòu)可以讓每個(gè)行為子關(guān)心自己的實(shí)現(xiàn)方式,從而最大的降低軟件復(fù)雜度,方便功能添加和修改。逃離行為狀態(tài)機(jī)實(shí)現(xiàn)原型代碼: void
void BhEscape::Run(){
int bid = GetId();
// 狀態(tài)機(jī)實(shí)現(xiàn)
switch(state){
case 0: // 前方距離過(guò)小
if(GI_distance[DISTANCE_FORWORD] < 30){
GO_speed_left[bid] = 0;
GO_speed_right[bid] = 0;
GT_beh_action[ACTION_TYPE_MOTOR][bid] = true;
timestart = millis();
state++; // 狀態(tài)變化
}else{
GT_beh_action[ACTION_TYPE_MOTOR][bid] = false;
}
break;
case 1SPAN style="mso-spacerun: yes"> // 觀察左右距離
if(millis() - timestart > 1000){
GO_eyeAngle[bid] = 0;
GT_beh_action[ACTION_TYPE_HEAD][bid] = true;
timestart = millis();
state++;
}
case 2SPAN style="mso-spacerun: yes"> // 觀察左右距離
if(millis() - timestart > 1000){
GO_eyeAngle[bid] = 180;
GT_beh_action[ACTION_TYPE_HEAD][bid] = true;
timestart = millis();
state++;
}
case 3SPAN style="mso-spacerun: yes"> // 決定往哪邊轉(zhuǎn)彎
if(millis() - timestart > 1000){
GO_eyeAngle[bid] = Angle_Center_90;
GT_beh_action[ACTION_TYPE_HEAD][bid] = true;
if(GI_distance[DISTANCE_LEFT_1] > GI_distance[DISTANCE_RIGHT_1]){
// 左轉(zhuǎn)
GO_speed_left[bid] = 0;
GO_speed_right[bid] = 255;
}else{
//右轉(zhuǎn)
GO_speed_left[bid] = 255;
GO_speed_right[bid] = 0;
}
GT_beh_action[ACTION_TYPE_MOTOR][bid] = true;
state = 0;
Delay(2000);
}
default:
break;
}
}
這種基于行為單元的實(shí)現(xiàn)方法比較類似生物的反射行為,完整的代碼在下載專區(qū)進(jìn)行下載。完成了基本的代碼,下一部分需要構(gòu)建機(jī)器人的機(jī)構(gòu)和測(cè)試了。
結(jié)構(gòu)和測(cè)試 實(shí)驗(yàn)機(jī)器人的結(jié)構(gòu)就地取材,用了一個(gè)拼裝玩具小車的零件,如下圖:
為了安裝電機(jī)和傳感器,重新拼裝了下,變成這個(gè)樣子:
有了基本的結(jié)構(gòu),可以測(cè)試功能了,驗(yàn)證功能是否正常。
功能測(cè)試完成,放到地上實(shí)際跑一下:
有點(diǎn)好玩,基本達(dá)到可以巡航和壁障的功能,不過(guò)功能太過(guò)于簡(jiǎn)單,只能相當(dāng)于一個(gè)玩具。
提交
自動(dòng)化機(jī)床的故障排除技術(shù)淺析
安川焊接機(jī)器人編程
ABB機(jī)器人控制軟件RobotWare應(yīng)用手冊(cè)SafeMove(英文)
ABB IRB7600 機(jī)器人維護(hù)信息
ABB IRC5P機(jī)器人培訓(xùn)教材